package iagovsothello.logger;

import iagovsothello.ai.Agent;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Observer;

public abstract class ExperimentContainer extends Experiment {

	private static final long serialVersionUID = 5312531518805169587L;
	protected List<BasicExperiment> list;
	protected int dimension;
	protected boolean basicPrint;
	
	public ExperimentContainer(String name, int dimension)
	{
		super(name,0);
		this.dimension = dimension;
		this.list = new LinkedList<BasicExperiment>();
		this.basicPrint = true;
	}
	
	public ExperimentContainer(String name, boolean print, boolean basicPrint, int dimension)
	{
		super(name,0,print);
		this.dimension = dimension;
		this.list = new LinkedList<BasicExperiment>();
		this.basicPrint = basicPrint;
	}
	
	public void add(String name, int rounds, Agent player1, Agent player2)
	{
		list.add(new BasicExperiment(name, basicPrint, dimension, rounds, player1.clone(), player2.clone()));
	}

	public int getDimension()
	{
		return dimension;
	}
	
	public long[] getMeanTimes(Agent player)
	{
		int N = (dimension*dimension-4)/2 + (dimension*dimension-4)%2;
		
		long[] times = new long[N];
		Arrays.fill(times, 0);
		int number = 0;
		
		for (BasicExperiment ex : list)
		{
			long[] exTimes = ex.getMeanTimes(player);
			if (exTimes != null)
			{
				for (int j = 0; j < exTimes.length; j++)
				{
					times[j] += exTimes[j];
				}
				number++;
			}
		}
		
		for (int j = 0; j < N; j++)
		{
			times[j] = times[j]/number;
		}
		return times;
	}
	
	public long getMaxTime(Agent player)
	{
		long maxTime = Long.MIN_VALUE;
		for (BasicExperiment ex : list)
		{
			long max = ex.getMaxTime(player);
			if (max > maxTime)
				maxTime = max;
		}
		return maxTime;
	}
	
	public int getVictories(Agent player)
	{
		int victories = -1;
		for (BasicExperiment ex : list)
		{
			int exVictories = ex.getVictories(player);
			if (exVictories >= 0)
			{
				if (victories == -1)
					victories = exVictories;
				else
					victories += exVictories;
			}
		}
		return victories;
	}
	
	public long[] getVisitedNodes(Agent player) 
	{
		int N = (dimension*dimension-4)/2 + (dimension*dimension-4)%2;
		
		long[] nodes = new long[N];
		Arrays.fill(nodes, 0);
		int number = 0;
		
		for (BasicExperiment ex : list)
		{
			long[] exNodes = ex.getVisitedNodes(player);
			if (exNodes != null)
			{
				for (int j = 0; j < exNodes.length; j++)
				{
					nodes[j] += exNodes[j];
				}
				number++;
			}
		}
		
		for (int j = 0; j < N; j++)
		{
			nodes[j] = nodes[j]/number;
		}
		return nodes;
	}
	
	@Override
	protected void execute() 
	{
		int currentIndex = getAndIncreaseIndex();
		int size = list.size();
		while (currentIndex < size)
		{
			list.get(currentIndex).start();
			currentIndex = getAndIncreaseIndex();
			setChanged();
			notifyObservers();
		}
	}

	public void addObserverRecursive(Observer o)
	{
		for (BasicExperiment exp : list)
		{
			exp.addObserverRecursive(o);
		}
	}
	
	@Override
	public int size() 
	{
		return list.size();
	}

	@Override
	public int totalSize() 
	{
		int size = 0;
		for (BasicExperiment exp : list)
		{
			size += exp.totalSize();
		}
		return size;
	}
	
	public void printRecursive()
	{
		for (BasicExperiment exp : list)
		{
			exp.printRecursive();
		}
		print();
	}
	
	protected Iterator<BasicExperiment> experimentIterator()
	{
		return list.iterator();
	}
}
